package cate.game.train.furniture;

import cate.common.table.d.GDFurniture;
import cate.common.table.d.GDObj;
import cate.common.table.item.furniture.row.FurnitureItemBaseRow;
import cate.common.table.item.furniture.row.FurnitureLevelUpRow;
import cate.common.table.item.furniture.row.FurnitureRandomAttrRow;
import cate.common.util.GameResult;
import cate.game.GameBody;
import cate.game.client.msg.MergeMsgSender;
import cate.game.event.RoleEventPublisher;
import cate.game.event.hero.HeroPowerChangeEvent;
import cate.game.res.*;
import cate.game.role.Role;
import cate.game.role.bag.furniture.Furniture;
import cate.game.role.bag.hero.Hero;
import cate.game.role.bag.vo.UidPosVO;
import cate.game.train.furniture.msg.FurnitureUpdateResp;
import cate.game.train.furniture.msg.FurnitureOffResp;
import cate.game.train.furniture.msg.FurnitureOnResp;
import cate.game.train.furniture.msg.FurnitureRecastResp;
import easy.java.practice.errorcode.EcResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;

public class TrainFurnitureHandler implements RoleEventPublisher {
    private Hero findHero(Role role, String heroUid) {
        if (StringUtils.isBlank(heroUid)) {
            return null;
        }
        return role.getBag().hero.getItem(heroUid);
    }

    private Furniture findFurniture(Role role, String furnitureUid, String heroUid, byte pos) {
        if (StringUtils.isBlank(furnitureUid)) {
            return null;
        }
        if (StringUtils.isNotBlank(heroUid)) {
            Hero hero = findHero(role, heroUid);
            if (hero != null) {
                Furniture furniture = hero.furnituresOn.getPosItem(pos);
                if (furniture != null) {
                    return furniture;
                }
                furniture = hero.furnituresOn.getFurniture(furnitureUid);
                if (furniture != null) {
                    return furniture;
                }
            }
        }
        return role.getBag().furniture.getItem(furnitureUid);
    }

    public GameResult<Void> levelUp(Role role, String furnitureUid, String heroUid, byte pos, CostSelect cs) {
        GameResult<Void> r = new GameResult<>();
        Furniture furniture = findFurniture(role, furnitureUid, heroUid, pos);
        if (furniture == null) {
            return r.fail("手办不存在");
        }
        FurnitureItemBaseRow baseRow = furniture.getTpl(role.toPlayBuildContext());
        if (baseRow == null) {
            return r.fail("手办不存在");
        }
        FurnitureLevelUpRow nowRow = role.getGame().table.furniture.levelUp.findRow(baseRow.protoId, furniture.level);
        if (nowRow == null || StringUtils.isBlank(nowRow.consumeStr)) {
            return r.fail("手办不可继续强化");
        }
        List<String> costUids = null;
        MixRes backReward = new MixRes();
        int remainNum = nowRow.costNum;
        if (remainNum > 0) {
            costUids = new ArrayList<>();
            if (cs != null) {
                for (Option option : cs.options) {
                    if (option.uidList == null) {
                        continue;
                    }
                    for (String costUid : option.uidList) {
                        Furniture cost = findFurniture(role, costUid, null, (byte) -1);
                        if (cost == null) {
                            return r.fail("选择的手办不存在");
                        }
                        FurnitureItemBaseRow costRow = cost.getTpl(role.toPlayBuildContext());
                        if (costRow == null) {
                            return r.fail("选择的手办不存在");
                        }
                        if (StringUtils.equals(furnitureUid, costUid) || baseRow.protoId != costRow.protoId) {
                            return r.fail("选择的手办有误");
                        }
                        costUids.add(costUid);
                        if (cost.level > 0) {
                            backReward.addList(rebornReward(role, baseRow.protoId, cost.tid, cost.level));
                        }
                    }
                }
            }
            if (costUids.size() < remainNum) {
                return r.fail("选择的手办数量不足");
            }
        }
        r = new MixResConsumer<Void>()
                .tips(true)
                .res(new MixRes(nowRow.consumeStr))
                .exe(role);
        if (!r.ok()) {
            return r;
        }
        if (cs != null && costUids != null) {
            for (String costUid : costUids) {
                role.getBag().furniture.removeItem(costUid, null);
            }
            if (!backReward.isEmpty()) {
                backReward.add(role, true);
                role.getGame().notice.dialogReward(role, backReward);
            }
        }
        furniture.level++;
        role.sendNow(new FurnitureUpdateResp(furniture, heroUid, pos));
        onUpdatePower(role, heroUid);
        role.getGame().notice.message(role, "强化成功");
        return r;
    }

    private MixRes rebornReward(Role role, int protoId, int costTid, int level) {
        MixRes resolveRes = new MixRes();
        FurnitureLevelUpRow levelUpRow = role.getGame().table.furniture.levelUp.findRow(protoId, level);
        if (levelUpRow != null) {
            FurnitureLevelUpRow noneLevelRow = role.getGame().table.furniture.levelUp.findRow(protoId, 0);
            resolveRes.addList(new MixRes(levelUpRow.resolveRewardStr));
            if (noneLevelRow != null) {
                resolveRes.minusList(new MixRes(noneLevelRow.resolveRewardStr));
            }
            int resolveBackNum = role.getGame().table.furniture.levelUp.findCostNum(protoId, level);
            if (resolveBackNum > 0) {
                for (int i = 0; i < resolveBackNum; ++i) {
                    resolveRes.addItem(new MixResItem(GDObj.Type.FURNITURE, costTid, 1));
                }
            }
        }
        return resolveRes;
    }

    private MixRes recycleReward(Role role, int tid, int protoId, int level) {
        MixRes resolveRes = new MixRes();
        FurnitureLevelUpRow levelUpRow = role.getGame().table.furniture.levelUp.findRow(protoId, level);
        if (levelUpRow != null) {
            resolveRes.addList(new MixRes(levelUpRow.resolveRewardStr));
            int resolveBackNum = role.getGame().table.furniture.levelUp.findCostNum(protoId, level);
            if (resolveBackNum > 0) {
                for (int i = 0; i < resolveBackNum; ++i) {
                    resolveRes.addItem(new MixResItem(GDObj.Type.FURNITURE, tid, 1));
                }
            }
        }
        return resolveRes;
    }

    public GameResult<Void> off(Role role, String heroUid, Set<Byte> posList) {
        GameResult<Void> r = new GameResult<>();
        Hero hero = findHero(role, heroUid);
        if (hero == null) {
            return r.fail("英雄不存在");
        }
        List<Byte> resPosList = new ArrayList<>();
        MergeMsgSender sender = new MergeMsgSender();
        for (byte pos : posList) {
            if (pos < 0 || pos > 34) {
                role.getGame().notice.message(role, "手办位置错误");
                continue;
            }
            GameResult<Byte> offRes = hero.offFurniture(role.toPlayBuildContext(), pos, sender);
            if (!offRes.ok()) {
                role.getGame().notice.message(role, offRes);
                continue;
            }
            resPosList.add(pos);
        }
        sender.send(role, true);
        role.sendNow(new FurnitureOffResp(heroUid, resPosList));
        onUpdatePower(role, heroUid);
        return r;
    }

    public GameResult<Void> on(Role role, String heroUid, List<UidPosVO> furnitures) {
        GameResult<Void> r = new GameResult<>();
        Hero hero = findHero(role, heroUid);
        if (hero == null) {
            return r.fail("英雄不存在");
        }
        Map<Byte, Furniture> furnitureMap = new HashMap<>();
        MergeMsgSender sender = new MergeMsgSender();
        for (UidPosVO vo : furnitures) {
            if (vo.pos < 0 || vo.pos > 34) {
                role.getGame().notice.message(role, "摆放位置错误");
                continue;
            }
            Furniture furniture = findFurniture(role, vo.uid, heroUid, vo.pos);
            if (furniture == null) {
                role.getGame().notice.message(role, "手办不存在");
                continue;
            }
            GameResult<Byte> onRes = hero.onFurniture(role.toPlayBuildContext(), furniture, vo.pos, sender);
            if (!onRes.ok()) {
                role.getGame().notice.message(role, onRes);
                continue;
            }
            furnitureMap.put(onRes.data, furniture);
        }
        sender.send(role, true);
        role.sendNow(new FurnitureOnResp(heroUid, furnitureMap));
        onUpdatePower(role, heroUid);
        role.getHistory().action.furnitureQualityOn();
        return r;
    }

    public GameResult<Void> reborn(Role role, String furnitureUid, String heroUid, byte pos) {
        GameResult<Void> r = new GameResult<>();
        Furniture furniture = findFurniture(role, furnitureUid, heroUid, pos);
        if (furniture == null) {
            return r.fail("手办不存在");
        }
        if (furniture.level == 0) {
            return r.fail("该手办无需重置");
        }
        FurnitureItemBaseRow baseRow = furniture.getTpl(role.getGame());
        if (baseRow == null) {
            return r.fail("该手办无法重置");
        }
        FurnitureLevelUpRow levelUpRow = role.getGame().table.furniture.levelUp.findRow(baseRow.protoId, furniture.level);
        if (levelUpRow == null) {
            return r.fail("该手办无法重置");
        }
        MixRes consume = new MixRes(levelUpRow.reforgeConsumeStr);
        int resolveBackNum = role.getGame().table.furniture.levelUp.findCostNum(baseRow.protoId, furniture.level);
        if (resolveBackNum > 0) {
            consume.multiply(resolveBackNum + 1);
        }
        EcResult<MixResItem> consumeRes = consume.consume(role);
        if (!consumeRes.ok()) {
            role.getGame().notice.tipResItem(role, consumeRes.data);
            return r.fail(consumeRes);
        }
        new MixResAdder()
                .setSendMailWhenFull(true)
                .setDialogReward(true)
                .setRes(rebornReward(role, furniture.getTpl(role.toPlayBuildContext()).protoId, furniture.tid, furniture.level))
                .exe(role);
        furniture.level = 0;
        role.sendNow(new FurnitureUpdateResp(furniture, heroUid, pos));
        onUpdatePower(role, heroUid);
        return r;
    }

    private void onUpdatePower(Role role, String heroUid) {
        if (StringUtils.isNotBlank(heroUid)) {
            publishEvent(role, new HeroPowerChangeEvent(role, role.getBag().hero.getItem(heroUid)));
            role.getBase().updatePower();
        }
    }

    public GameResult<Void> recycle(Role role, Set<String> uids, String heroUid, byte pos) {
        GameResult<Void> r = new GameResult<>();
        if (CollectionUtils.isEmpty(uids)) {
            return r.fail("回收列表为空");
        }
        if (StringUtils.isNotBlank(heroUid)) {
            Hero hero = findHero(role, heroUid);
            if (hero == null) {
                return r.fail("英雄不存在");
            }
            if (uids.size() > 1) {
                return r.fail("回收数量有误");
            }
        }
        MergeMsgSender sender = new MergeMsgSender();
        MixRes reward = new MixRes();
        for (String uid : uids) {
            Furniture furniture = findFurniture(role, uid, heroUid, pos);
            if (furniture == null) {
                role.getGame().notice.message(role, "手办不存在");
                continue;
            }
            FurnitureItemBaseRow baseRow = furniture.getTpl(role.toPlayBuildContext());
            if (baseRow == null) {
                role.getGame().notice.message(role, "手办不存在");
                continue;
            }
            FurnitureLevelUpRow levelUpRow = role.getGame().table.furniture.levelUp.findRow(baseRow.protoId, furniture.level);
            if (levelUpRow == null) {
                role.getGame().notice.message(role, "手办不可回收");
                continue;
            }
            reward.addList(recycleReward(role, baseRow.id, baseRow.protoId, furniture.level));
            if (StringUtils.isNotBlank(heroUid)) {
                Hero hero = findHero(role, heroUid);
                if (hero != null) {
                    hero.furnituresOn.doRealOff(pos, null);
                    role.sendNow(new FurnitureOffResp(heroUid, Collections.singletonList(pos)));
                    onUpdatePower(role, heroUid);
                }
            } else {
                role.getBag().furniture.removeItem(uid, sender);
            }
        }
        sender.send(role, true);
        if (reward.isEmpty()) {
            return r.fail("没有可以回收的手办");
        }
        new MixResAdder()
                .setSendMailWhenFull(true)
                .setDialogReward(true)
                .setRes(reward)
                .exe(role);
        return r;
    }

    public GameResult<Void> recast(Role role, String furnitureUid, String heroUid, byte pos,
                                   boolean useItem, byte camp, byte job, int campAttrId, int jobAttrId) {
        GameResult<Void> r = new GameResult<>();
        Furniture furniture = findFurniture(role, furnitureUid, heroUid, pos);
        if (furniture == null) {
            return r.fail("手办不存在");
        }
        r = checkRecastParam(role.getGame(), furniture, useItem, camp, job, campAttrId, jobAttrId);
        if (!r.ok()) {
            return r;
        }
        FurnitureItemBaseRow baseRow = furniture.getTpl(role.toPlayBuildContext());
        if (baseRow == null) {
            return r.fail("手办不存在");
        }
        FurnitureLevelUpRow levelRow = role.getGame().table.furniture.levelUp.findRow(baseRow.protoId, furniture.level);
        if (levelRow == null) {
            return r.fail("该手办无法洗练");
        }
        MixRes consume = new MixRes(levelRow.reforgeConsumeStr);
        if (useItem) {
            consume.addList(new MixRes(GDFurniture.RECAST_ITEM_STR));
        } else {
            int num = camp > 0 ? 1 : 0;
            num += job > 0 ? 1 : 0;
            if (num == 1) {
                consume.addList(new MixRes(levelRow.lock1ConsumeStr));
            } else if (num == 2) {
                consume.addList(new MixRes(levelRow.lock2ConsumeStr));
            }
        }
        new MixResConsumer<Void>()
                .tips(true)
                .res(consume)
                .success(e -> {
                    furniture.recastAttr(camp, job, campAttrId, jobAttrId);
                    role.sendNow(new FurnitureRecastResp(furniture, heroUid, pos));
                    return null;
                })
                .exe(role);
        return r;
    }

    private GameResult<Void> checkRecastParam(GameBody game,
                                              Furniture furniture,
                                              boolean useItem,
                                              byte camp,
                                              byte job,
                                              int campAttrId,
                                              int jobAttrId) {
        GameResult<Void> r = new GameResult<>();
        FurnitureItemBaseRow baseRow = furniture.getTpl(game.fight.getPlayBuildContext());
        if (camp > 0 && (baseRow.camps.isEmpty() || !baseRow.camps.contains(camp))) {
            return r.fail("错误的阵营");
        }
        if (job > 0 && (baseRow.jobs.isEmpty() || !baseRow.jobs.contains(job))) {
            return r.fail("错误的职业");
        }
        if (useItem) {
            if (!baseRow.camps.isEmpty() && campAttrId < 1) {
                return r.fail("请选择阵营属性");
            }
            if (!baseRow.jobs.isEmpty() && jobAttrId < 1) {
                return r.fail("请选择职业属性");
            }
            if (campAttrId > 0) {
                FurnitureRandomAttrRow campAttrRow = game.table.furniture.randomAttr.get(campAttrId);
                if (campAttrRow == null || baseRow.camp1Group != campAttrRow.group) {
                    return r.fail("错误的阵营属性");
                }
            }
            if (jobAttrId > 0) {
                FurnitureRandomAttrRow jobAttrRow = game.table.furniture.randomAttr.get(jobAttrId);
                if (jobAttrRow == null || baseRow.job1Group != jobAttrRow.group) {
                    return r.fail("错误的职业属性");
                }
            }
        } else {
            if (campAttrId > 0 || jobAttrId > 0) {
                return r.fail("普通洗练无法选择属性");
            }
            if (camp > 0 && camp != furniture.camp) {
                return r.fail("普通洗练无法更改阵营");
            }
            if (job > 0 && job != furniture.job) {
                return r.fail("普通洗练无法更改职业");
            }
        }
        return r;
    }

    public GameResult<Void> save(Role role, String uid, String heroUid, byte pos) {
        GameResult<Void> r = new GameResult<>();
        Furniture furniture = findFurniture(role, uid, heroUid, pos);
        if (furniture == null) {
            return r.fail("手办不存在");
        }
        furniture.save();
        role.sendNow(new FurnitureUpdateResp(furniture, heroUid, pos));
        role.getGame().notice.message(role, "洗练保存成功");
        if (heroUid != null) {
            onUpdatePower(role, heroUid);
        }
        return r.success();
    }
}
